﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Game
{
    /*-------------------------------------------------------------------------
    | ITriggerEvent:
    | ------------
    | Interface trigger event callback
    |---------------------------------------------------------------------------*/
    public interface IGameObjectTriggerEvent
    {
        void OnEnter(GameObject sender);
        void OnLeave(GameObject sender);
        void OnStay(GameObject sender);
    }

    public interface IGameObjectHitEvent
    {
        void OnHit(GameObject sender, IDK.Vector3 impactForce);
    }


    /*-------------------------------------------------------------------------
    | ITriggerEventSystem:
    | ------------
    | Interface trigger event manager
    |---------------------------------------------------------------------------*/
    public abstract class GameObjectManagerBase : ISceneTriggerListener, ISceneHitListener
    {
        protected Dictionary<String, IGameObjectTriggerEvent> Triggers = new Dictionary<String, IGameObjectTriggerEvent>();
        protected Dictionary<String, IGameObjectHitEvent> Hits = new Dictionary<String, IGameObjectHitEvent>();

        public Dictionary<String, GameObject> GameObjects = new Dictionary<String, GameObject>();
        public Dictionary<String, GameObjectInfo> GameObjectsType = new Dictionary<String, GameObjectInfo>();

        public void Clear()
        {
            GameObjects.Clear();
            GameObjectsType.Clear();
            Triggers.Clear();
        }

        public bool HasGameObject(String name)
        {
            return GameObjectsType.ContainsKey(name);
        }

        //
        public void OnEnter(String sender, String other)
        {
            Triggers[sender].OnEnter(GameObjects[other]);
        }

        public void OnLeave(String sender, String other)
        {
            Triggers[sender].OnLeave(GameObjects[other]);
        }

        public void OnStay(String sender, String other)
        {
            Triggers[sender].OnStay(GameObjects[other]);
        }

        public void OnLeaveToAll(GameObject obj)
        {
            foreach (var it in Triggers)
            {
                it.Value.OnLeave(obj);
            }
        }

        public void OnHit(String a, String b, IDK.Vector3 impactForce)
        {
            if(Hits.ContainsKey(a))
            {
                Hits[a].OnHit(GameObjects[b], impactForce);
            }

            if (Hits.ContainsKey(b))
            {
                Hits[b].OnHit(GameObjects[a], impactForce);
            }
        }
    }

    /*-------------------------------------------------------------------------
    | GameObjectManager:
    | ------------
    | 
    |---------------------------------------------------------------------------*/
    public class GameObjectManager : GameObjectManagerBase, IManager
    {

        public GameObjectManager()
        {
        }

        public GameObject CreateGameObject(String name, WorldScene scene)
        {
            //create instance
            var instance = GameObjectsType[name].CreateInstance(scene);
            GameObjects.Add(name, instance);

            if (instance is IGameObjectTriggerEvent)
            {
                Triggers.Add(name, instance as IGameObjectTriggerEvent);
            }

            if (instance is IGameObjectHitEvent)
            {
                Hits.Add(name, instance as IGameObjectHitEvent);
            }


            return instance;
        }

        public void DeleteGameObject(String name, WorldScene scene)
        {
            var instance = GameObjects[name];

            if (instance is IGameObjectTriggerEvent)
            {
               //notificate all 
               OnLeaveToAll(instance);

               //remove trigger
               Triggers.Remove(name);
            }

            if (instance is IGameObjectHitEvent)
            {
                Hits.Remove(name);
            }

            GameObjectsType[name].RemoveInstance(GameObjects[name], scene);
            GameObjects.Remove(name);
        }

        public virtual void Update(Events.ProcessSceneUpdate evnt)
        {
            //NOTE : copy for valid iterator
            Dictionary<String, GameObject> container = new Dictionary<string,GameObject>(GameObjects);

            foreach (KeyValuePair<String, GameObject> it in container)
            {
                it.Value.OnUpdate(evnt);
            }
        }

        public virtual void Invalidate()
        {
            foreach (KeyValuePair<String, GameObject> it in GameObjects)
            {
                it.Value.Invalidate();
            }
        }
    }
}
